﻿using System;
using System.Collections.Generic;
using System.Linq;
using mqtttLib.Helper;
using mqtttLib.Messages.Base;

namespace mqtttLib.Messages
{
    /// <summary>
    /// 主题 消息model
    /// </summary>
    public struct TopicQos
    {
        public string Topic { get; set; }
        public Qos Qos { get; set; }
    }


    /// <summary>
    ///  订阅返回
    /// </summary>
    [Flags]
    public enum SubscribeAckCode : byte
    {
        /// <summary>
        ///     QOS  0 - 消息不能保证传递。没有重试，保证了传递成功。
        /// </summary>
        AtMostOnce = 0,
        /// <summary>
        ///     QOS  1 - 消息保证交付。它将至少交付一次，但可以交付。
        ///     如果发生网络错误，则不止一次。
        /// </summary>
        AtLeastOnce = 1,
        /// <summary>
        ///     QOS  2 - Message will be delivered once, and only once. Message will be retried until
        ///     它是成功发送的
        /// </summary>
        ExactlyOnce = 2,
        /// <summary>
        /// Failure  失败
        /// </summary>
        Failure = 0x80
    }

    /// <summary>
    /// 订阅消息
    /// </summary>
    public sealed class SubscribeMessage : MqttMessagePacketId
    {
        public SubscribeMessage()
            : base(MessageType.SUBSCRIBE)
        {
        }
        /// <summary>
        /// 主题
        /// </summary>
        public List<TopicQos> Topics = new List<TopicQos>();
        /// <summary>
        /// 添加订阅消息
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="qos"></param>
        public void Subscribe(string topic, Qos qos)
        {
            Topics.Add(new TopicQos
            {
                Topic = topic,
                Qos = qos,
            });
        }
        public override byte[] GetDataBytes()
        {

            var result = new LinkedList<byte>();
            //variable header
            if (FixedHeader.Qos == Qos.AtLeastOnce || FixedHeader.Qos == Qos.ExactlyOnce)
            {
                PacketIdentifier = GetPacketIdentifier();
                result.AddLast(PacketIdentifier);
            }
            //有效载荷
            foreach (var item in Topics)
            {
                result.AddLast(item.Topic);        //主题
                result.AddLast((byte)item.Qos);      //质量
            }
            FixedHeader.RemaingLength = result.Count;
            result.AddFirst(FixedHeader.GetDataBytes());
            return result.ToArray();
        }

        public override void GetDataObject(byte[] buffers)
        {
            int offset = 2;  // int offset = GetStartOffset(buffers);  // int offset = buffers.Length - FixedHeader.RemaingLength;
            //variable header
            if (FixedHeader.Qos == Qos.AtLeastOnce || FixedHeader.Qos == Qos.ExactlyOnce)
                PacketIdentifier = buffers.ReadShort(ref offset);
            if (buffers.Length > 2)
            {
                while (buffers.Length > offset)
                {
                    Topics.Add(new TopicQos
                    {
                        Topic = buffers.ReadString(ref offset),
                        Qos = (Qos)buffers.Read(ref offset, 1)[0],
                    });


                }
            }

        }
    }



    /// <summary>
    /// 订阅消息 返回
    /// </summary>
    public class SubscribeAckMessage : MqttMessagePacketId
    {


        public SubscribeAckMessage()
            : base(MessageType.SUBACK)
        {

        }
        /// <summary>
        /// 有效载荷包含一个返回码清单。每个返回码对应等待确认的SUBSCRIBE报文中的一个主题过滤器。返回码的顺序必须和SUBSCRIBE报文中主题过滤器的顺序相同
        /// </summary>
        public SubscribeAckCode[] Payload { get; set; }

        public override byte[] GetDataBytes()
        {

            var result = new LinkedList<byte>();
            //variable header
            if (FixedHeader.Qos == Qos.AtLeastOnce || FixedHeader.Qos == Qos.ExactlyOnce)
            {
                //   PacketIdentifier = GetPacketIdentifier();
                result.AddLast(PacketIdentifier);
            }
            foreach (var item in Payload)
            {
                result.AddLast((byte)item);
            }
            FixedHeader.RemaingLength = result.Count;
            result.AddFirst(FixedHeader.GetDataBytes());
            return result.ToArray();
        }


        public override void GetDataObject(byte[] buffers)
        {
            int offset = GetStartOffset(buffers);  // int offset = buffers.Length - FixedHeader.RemaingLength;
            if (offset < FixedHeader.RemaingLength)
            {
                if (FixedHeader.Qos == Qos.AtLeastOnce || FixedHeader.Qos == Qos.ExactlyOnce)
                    PacketIdentifier = buffers.ReadShort(ref offset);
                // StateCode = (SubscribeAckCode)buffers.ReadShort(ref offset);

                if (buffers.Length > 2)
                {
                    Payload = new SubscribeAckCode[buffers.Length - offset];
                    byte[] data = buffers.Read(ref offset, buffers.Length - offset);
                    for (int i = 0; i < data.Length; i++)
                    {
                        Payload[i] = (SubscribeAckCode)data[i];
                    }
                }
            }

        }

    }
}